package config

import (
	"go.uber.org/zap/zapcore"
	"time"
)

type Zap struct {
	// 日志级别
	Level string `mapstructure:"level" json:"level" yaml:"level"`
	// 日志前缀
	Prefix string `mapstructure:"prefix" json:"prefix" yaml:"prefix"`
	// 日志输出格式：json/console
	Format string `mapstructure:"format" json:"format" yaml:"format"`
	// 日志存储目录
	Director string `mapstructure:"director" json:"director" yaml:"director"`
	// 日志编码器级别
	EncodeLevel string `mapstructure:"encode-level" json:"encode-level" yaml:"encode-level"`
	// 用于定义日志条目中堆栈跟踪信息的键名
	StacktraceKey string `mapstructure:"stacktrace-key" json:"stacktrace-key" yaml:"stacktrace-key"`
	// 是否显示行号
	ShowLine bool `mapstructure:"show-line" json:"show-line" yaml:"show-line"`
	// 是否在控制台显示
	LogInConsole bool `mapstructure:"log-in-console" json:"log-in-console" yaml:"log-in-console"`
}

// Levels 根据日志级别字符串转化为 zapcore.Levels
func (c *Zap) Levels() []zapcore.Level {
	levels := make([]zapcore.Level, 0, 7)
	// 将c.Level字符串解析为一个zapcore.Level类型的值。如果解析成功，level变量将包含对应的日志级别
	level, err := zapcore.ParseLevel(c.Level)
	if err != nil {
		level = zapcore.DebugLevel
	}
	// zapcore库定义的日志级别是连续的，并且zapcore.FatalLevel是第5个日志级别
	for ; level <= zapcore.FatalLevel; level++ {
		levels = append(levels, level)
	}
	return levels
}

func (c *Zap) Encoder() zapcore.Encoder {
	// 定义了日志条目中各个字段的键名。
	config := zapcore.EncoderConfig{
		LevelKey:      "level",
		TimeKey:       "time",
		NameKey:       "name",
		CallerKey:     "caller",
		MessageKey:    "message",
		StacktraceKey: c.StacktraceKey,
		LineEnding:    zapcore.DefaultLineEnding, // 定义了日志条目之间的行结束符
		EncodeTime: func(t time.Time, encoder zapcore.PrimitiveArrayEncoder) {
			encoder.AppendString(c.Prefix + t.Format("2006-01-02 15:04:05.000"))
		}, // 定义了一个自定义的时间编码函数，它将时间格式化为字符串，并在前面添加一个前缀
		EncodeLevel:    c.LevelEncoder(),               // 调用LevelEncoder方法来获取日志级别的编码器
		EncodeCaller:   zapcore.FullCallerEncoder,      // 定义了调用者信息的编码方式。
		EncodeDuration: zapcore.SecondsDurationEncoder, // 定义了持续时间（例如，日志条目的时间戳）的编码方式。
	}
	// zapcore.NewConsoleEncoder 是 zap 日志库中的一个函数，用于创建一个控制台编码器。
	// 这个编码器将日志条目格式化为适合在控制台上显示的格式。与 zapcore.NewJSONEncoder 不同，
	// zapcore.NewConsoleEncoder 生成的日志输出是可读的文本格式，而不是 JSON 格式。
	if c.Format == "json" {
		return zapcore.NewJSONEncoder(config)
	}
	return zapcore.NewConsoleEncoder(config)
}

// LevelEncoder 根据 EncodeLevel 返回 zapcore.LevelEncoder，返回不同级别的日志编码器
func (c *Zap) LevelEncoder() zapcore.LevelEncoder {
	switch {
	case c.EncodeLevel == "LowercaseLevelEncoder": // 小写编码器(默认)
		return zapcore.LowercaseLevelEncoder
	case c.EncodeLevel == "LowercaseColorLevelEncoder": // 小写编码器带颜色
		return zapcore.LowercaseColorLevelEncoder
	case c.EncodeLevel == "CapitalLevelEncoder": // 大写编码器
		return zapcore.CapitalLevelEncoder
	case c.EncodeLevel == "CapitalColorLevelEncoder": // 大写编码器带颜色
		return zapcore.CapitalColorLevelEncoder
	default:
		return zapcore.LowercaseLevelEncoder
	}
}
